package br.org.acessobrasil.portal.action;

import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.NoResultException;

import org.apache.log4j.Logger;

import br.com.goals.tableedit.util.MD5;
import br.org.acessobrasil.portal.Gerenciador;
import br.org.acessobrasil.portal.excecoes.ErroValidacaoException;
import br.org.acessobrasil.portal.modelo.ArquivoLog;
import br.org.acessobrasil.portal.modelo.Privilegio;
import br.org.acessobrasil.portal.modelo.Setor;
import br.org.acessobrasil.portal.modelo.Sitio;
import br.org.acessobrasil.portal.modelo.Usuario;
import br.org.acessobrasil.portal.persistencia.LogDao;
import br.org.acessobrasil.portal.persistencia.PerfilDaoSpring;
import br.org.acessobrasil.portal.persistencia.PrivilegioDao;
import br.org.acessobrasil.portal.persistencia.SetorDao;
import br.org.acessobrasil.portal.persistencia.SitioDaoSpring;
import br.org.acessobrasil.portal.persistencia.UsuarioDaoSpring;
import br.org.acessobrasil.portal.util.LoginInterceptor;
/**
 * Controla as acoes que manipulam os usuarios
 * @author Fabio Issamu Oshiro
 *
 */
public class UsuarioAction extends Super{
	private static final long serialVersionUID = 34L;
	private static Logger logger = Logger.getLogger(UsuarioAction.class);
	
	public static final int SENHA_TAMANHO_MIN = 8;
	
	private static UsuarioDaoSpring usuarioDao;//atribuido pelo spring
	private static SetorDao setorDao;//atribuido pelo spring
	private static PerfilDaoSpring perfilDao;// atribuido pelo spring
	private static SitioDaoSpring sitioDao;// atribuido pelo spring
	private static PrivilegioDao privilegioDao;
	

	ArquivoLog logg = new ArquivoLog();
	private LogDao logDao = LogDao.getInstance(); 
	
	private List<Usuario> listUsuario;
	private List<Setor> listSetor;
	//private List<Perfil> listPerfil;
	private List<Sitio> listSitio;
	private List<Sitio> listSitioAtual;

	private Usuario usuario;

	private String coSenha;
	private String confirmacaoSenha;
	
	private String senhaAtual;
	
	private Sitio[] arraySitiosAtuais;
	private String[] arraySitios;
	
	public UsuarioAction(UsuarioDaoSpring usuarioDao,SetorDao setorDao,PerfilDaoSpring perfilDao, SitioDaoSpring sitioDao, PrivilegioDao privilegioDao){
		UsuarioAction.usuarioDao = usuarioDao;
		UsuarioAction.setorDao = setorDao;
		UsuarioAction.perfilDao = perfilDao;
		UsuarioAction.sitioDao = sitioDao;
		UsuarioAction.privilegioDao = privilegioDao;
	}
	
	/**
	 * Remove o usuario e todas as suas dependencias
	 * @return INPUT || SUCCESS
	 * @throws Exception
	 */
	public String apagarUsuario() throws Exception{
		if(btnCancelar==null && requestKeyOk()){
			//nao pressionou o cancelar
			usuarioDao.apagar(usuario.getNuUsuario());
			return SUCCESS;
		}else if(btnCancelar!=null){
			return SUCCESS;
		}else{
			gerarRequestKey();
			usuario = usuarioDao.select(usuario.getNuUsuario());
			return INPUT;
		}
	}
	
	public String atualizarInfoPessoais(){
		Usuario usuarioLogado = getUsuarioLogado();
		try{
			if(!usuarioLogado.equals(this.usuario)){
				return ILEGAL_ACTION;
			}
			Usuario usuarioDB = usuarioDao.select(usuario.getNuUsuario());
			if(usuarioDB.getCoSenha().equals(MD5.toPassword(senhaAtual))){
				usuarioDB.setNoUsuario(usuario.getNoUsuario());
				usuarioDB.setNoEmail(usuario.getNoEmail());
				usuarioDB.setNuTelefone(usuario.getNuTelefone());
				usuarioDB.setPerfil(usuarioLogado.getPerfil());
				usuarioDB.setSetor(usuarioLogado.getSetor());
				usuarioDB.setListPrivilegio(usuarioLogado.getListPrivilegio());
				usuarioDB.setListSitio(usuarioLogado.getListSitio());
				usuario = usuarioDB;
				verificarCampos();
				usuarioDao.update(usuarioDB);
				//atualiza na sessao
				getRequest().getSession().setAttribute(LoginInterceptor.USER_HANDLE, usuarioDB);				
				usuarioLogado.addActionMessage("As suas informa&ccedil;&atilde;es foram atualizadas.");
			}else{
				usuario = usuarioDB;
				usuarioLogado.addActionError("A senha atual est&aacute; diferente.");
				return INPUT;
			}
		}catch(Exception e){
			usuarioLogado.addActionError(e.getMessage());
			return INPUT;
		}
		return SUCCESS;
	}
	
	public String abrirInfoPessoais(){
		Usuario usuarioLogado = getUsuarioLogado();
		if(usuarioLogado.equals(this.usuario)){
			carregarUsuario();
			return SUCCESS;
		}else{
			return ILEGAL_ACTION;
		}
	}
	
	public String listar() {
		setListUsuario(usuarioDao.getList(getUsuarioLogado(),getSitioAtual()));
		return SUCCESS;
	}

	/**
	 * Ativa um usuario
	 * @return String
	 */
	public String ativarUsuario(){
		try {
			usuario = usuarioDao.select(usuario.getNuUsuario());
			usuario.setCoAtivo(true);
			usuarioDao.update(usuario);
			Usuario usuarioLogado = getUsuarioLogado();
			logDao.addLog(usuarioLogado," Usu&aacute;rio Ativado [ '"+usuario.getNoUsuario()+"', login='"+usuario.getCoUsuario()+"', ID="+usuario.getNuUsuario()+"].");
		} catch (Exception e) {
			logger.error("Erro ao ativar um usuario " + usuario,e);
		}
		
		return SUCCESS;
	}
	/**
	 * Desativa um usuario
	 * @return String
	 */
	public String desativarUsuario(){
		try {
			usuario = usuarioDao.select(usuario.getNuUsuario());
			usuario.setCoAtivo(false);
			usuarioDao.update(usuario);
			Usuario usuarioLogado = getUsuarioLogado();
			logDao.addLog(usuarioLogado," Usu&aacute;rio Desativado [ "+usuario.getNoUsuario()+" ] .");
		} catch (Exception e) {
			logger.error("Erro ao desativar um usuario " + usuario,e);
		}
		return SUCCESS;
	}
	
	/**
	 * Trata a senha do usu�rio caso ele queira trocar
	 * @throws Exception
	 */
	private void verificarCampos() throws ErroValidacaoException, Exception{
		Usuario usuarioLogado = getUsuarioLogado();
		Usuario tempUsuario = usuarioDao.procura(usuario.getCoUsuario());
		if(tempUsuario!=null && !tempUsuario.getNuUsuario().equals(usuario.getNuUsuario())){
			throw new ErroValidacaoException("J&aacute; existe um usu&aacute;rio '"+usuario.getCoUsuario()+"', por favor escolha outro.");
		}
		if (coSenha!=null && !coSenha.equals("")) {
			if(coSenha.length()<SENHA_TAMANHO_MIN){
				throw new ErroValidacaoException("A senha deve conter no m&aacute;nimo "+SENHA_TAMANHO_MIN+" caracteres.");
			}
			if (!coSenha.equals(this.confirmacaoSenha)) {
				throw new ErroValidacaoException("A confirma&ccedil;&atilde;o de senha est&aacute; diferente.");
			}
			try {
				usuario.setCoSenha(MD5.toPassword(coSenha));
			} catch (NoSuchAlgorithmException e) {
				logger.error("Erro ao verificarCampos ",e);
				throw new Exception("O algoritimo MD5 nao foi encontrado. Contate o administrador.");
			}
		}
		if(usuario.getNoEmail()==null || usuario.getNoEmail().equals("")){
			usuarioLogado.addActionError("O e-mail &eacute; obrigat&oacute;rio!");
		}
		if(usuario.getNoUsuario()==null || usuario.getNoUsuario().equals("")){
			usuarioLogado.addActionError("O nome &eacute; obrigat&oacute;rio!");
		}
		if(usuario.getCoUsuario()==null || usuario.getCoUsuario().equals("")){
			usuarioLogado.addActionError("O usu&aacute;rio &eacute; obrigat&oacute;rio!");
		}
		if(usuario.getNuTelefone()==null || usuario.getNuTelefone().equals("")){
			usuarioLogado.addActionError("O telefone &eacute; obrigat&oacute;rio!");
		}
	}
	
	/**
	 * Cadastra um usuario
	 * @return SUCCESS INPUT
	 */
	public String adicionarUsuario(){
		if(usuario==null){
			return setTextoPredefinidoUsuario();
		}
		if(getBtnGravar()!=null){
			Usuario usuarioLogado = getUsuarioLogado();
			try {
				if (usuario.getNuHierarquia() < usuarioLogado.getNuHierarquia()){
					usuarioLogado.addActionError("N&atilde;o &eacute; poss&iacute;vel cadastrar um usu&aacute;rio com uma hierarquia maior que a sua atual.");
					return INPUT;
				}
				
				
				usuario.setDtCriacao(new Date());
				usuario.setCoAtivo(true);
				//validacao somente no cadastro
				if(coSenha==null || coSenha.equals("")){
					usuarioLogado.addActionError("A senha &eacute; obrigat&oacute;ria!");
				}else if(confirmacaoSenha==null || confirmacaoSenha.equals("")){
					usuarioLogado.addActionError("A confirma&ccedil;&atilde;o de senha &eacute; obrigat&oacute;ria!");
				}
				verificarCampos();
				usuario.setDtAlteracao(new Date());
				usuario.setListSitio(new ArrayList<Sitio>());
				
				if(arraySitios != null && arraySitios.length > 0){
					for (String sitio : arraySitios) {
						Privilegio privilegio = new Privilegio();
						Sitio sitioAtual = sitioDao.select(Long.parseLong(sitio));
						if(getRequest().getParameter(sitio+"_perfil") != null){
							long nuPerfil = Long.parseLong(getRequest().getParameter(sitio+"_perfil"));
							privilegio.setPerfil(perfilDao.select(nuPerfil));
						}
						if(getRequest().getParameter(sitio+"_setor") != null){
							long nuSetor =  Long.parseLong(getRequest().getParameter(sitio+"_setor"));
							privilegio.setSetor(setorDao.select(nuSetor));
						}
						privilegio.setSitio(sitioAtual);
						privilegio.setUsuario(usuario);
						privilegioDao.create(privilegio);
						usuario.getListSitio().add(sitioAtual);
					}
				}
				if(usuario.getListSitio() == null || usuario.getListSitio().size() == 0){
					usuarioLogado.addActionError("N&atilde;o &eacute; poss&iacute;vel cadastrar um usu&aacute;rio sem s&iacute;tio.");
					return INPUT;
				}
				usuarioDao.create(usuario);
				//usuarioDao.update(usuario);
				getListSitio();
				for (Sitio sitio : listSitio) {
					sitio.setListPerfil(perfilDao.list(sitio));
					sitio.setListSetor(setorDao.list(sitio));
				}		
				usuario=null;
				setTextoPredefinidoUsuario();
				usuarioLogado.addActionMessage("Usuario adicionado com sucesso.");
				mensagem = "Usu&aacute;rio adicionado."+" [ "+usuario.getNoUsuario()+" ] .";
				logDao.addLog(usuarioLogado,mensagem);
				
			} catch (Exception e) {
				usuarioLogado.addActionError(e.getMessage());
				logger.error("Erro ao adicionarUsuario "+getUsuario(),e);
			}
		}else{
			return setTextoPredefinidoUsuario();
		}
		return SUCCESS;
	}
	
	/**
	 * Atualiza um usuario
	 * @return ILEGAL_ACTION, INPUT, FAZER_LOGIN, SUCCESS
	 */
	public String atualizarUsuario() {
		//if(usuario.getNuUsuario().equals(1L)){
		//	return ILEGAL_ACTION;
		//}
		Usuario usuarioLogado = getUsuarioLogado();
		try {
			if (usuario.getNuHierarquia() < usuarioLogado.getNuHierarquia()){
				usuarioLogado.addActionError("N&atilde;o &eacute; poss&iacute;vel alterar um usu&aacute;rio para uma hierarquia maior que a sua atual.");
				return INPUT;
			} 
			Usuario usuarioBanco = usuarioDao.select(usuario.getNuUsuario());
			if(usuarioBanco.getNuUsuario().equals(1L) && !usuarioLogado.getNuUsuario().equals(1L)){
				usuarioLogado = usuarioDao.select(usuarioLogado.getNuUsuario());
				usuarioLogado.setCoAtivo(false);
				usuarioDao.update(usuarioLogado);
				mensagem = "Usu&aacute;rio ID "+ usuarioLogado.getNuUsuario()+" tentou atualizar o root do sistema e foi desabilitado.";
				logDao.addLog(usuarioLogado,mensagem);
				limparSessao();
				usuarioLogado.addActionError(getText("label.comando_ilegal"));
				return FAZER_LOGIN;
			}
			
			usuario.setDtCriacao(usuarioBanco.getDtCriacao());
			usuario.setCoSenha(usuarioBanco.getCoSenha());
			usuario.setCoAtivo(usuarioBanco.isCoAtivo());
			//faz o tratamento de senha do usuario
			verificarCampos();
			Date agora = new Date();
			usuario.setDtAlteracao(agora);
			usuario.setListSitio(new ArrayList<Sitio>());
			//L�gica de escolha de sitios
			if(arraySitios != null && arraySitios.length > 0){
				//Remove da lista de sitios do usuario os sitios antigos
				usuario.setListSitio(new ArrayList<Sitio>());
				
				//Adiciona os sitios marcados no checkbox e insere respectivos privilegios
				for (String sitio : arraySitios) {
					Sitio sitioAtual = sitioDao.select(Long.parseLong(sitio));
					Privilegio privilegio;
					try{
						privilegio = privilegioDao.select(usuario,sitioAtual);
					}catch (Exception e) {
						privilegio = new Privilegio();
					}
					if(getRequest().getParameter(sitio+"_perfil") != null){
						long nuPerfil = Long.parseLong(getRequest().getParameter(sitio+"_perfil"));
						privilegio.setPerfil(perfilDao.select(nuPerfil));
					}
					if(getRequest().getParameter(sitio+"_setor") != null){
						long nuSetor =  Long.parseLong(getRequest().getParameter(sitio+"_setor"));
						privilegio.setSetor(setorDao.select(nuSetor));
					}
					privilegio.setSitio(sitioAtual);
					privilegio.setUsuario(usuario);
					privilegioDao.update(privilegio);
					usuario.getListSitio().add(sitioAtual);
				}
			}		
			usuarioDao.update(usuario);
			mensagem = "Usu&aacute;rio atualizado."+" [ "+usuario.getNoUsuario()+" ] .";
			
			usuarioLogado.addActionMessage("Usu&aacute;rio atualizado com sucesso.");
			logDao.addLog(usuarioLogado,mensagem);
		
			//Atualizar sitios sessao ap�s alterar o pr�prio perfil
			if(usuario.getNuUsuario().equals(usuarioLogado.getNuUsuario())){
				usuario.setSetor(usuarioLogado.getSetor());
				usuario.setPerfil(usuarioLogado.getPerfil());
				getRequest().getSession().setAttribute(LoginInterceptor.USER_HANDLE, usuario);
				if(usuario.getListSitio().size() >= 1){
					if(usuarioLogado.getListSitio().size() == 0)
						getRequest().getSession().setAttribute(Super.SITIO_LOGADO, usuario.getListSitio().get(0));
				}else{
					getRequest().getSession().setAttribute(Super.SITIO_LOGADO,null);
				}
			}
			
			//Recarrega as informacoes do usuario
			carregarUsuario();
			return SUCCESS;
		} catch(ErroValidacaoException e){
			usuarioLogado.addActionMessage(e.getMessage());
			//Recarrega as informacoes do usuario
			carregarUsuario();
		} catch (Exception e) {
			usuarioLogado.addActionMessage(e.getMessage());
			//Recarrega as informacoes do usuario
			carregarUsuario();
			logger.error("Erro ao atualizar o usuario " + usuario,e);
		}
		return INPUT;
	}

	/**
	 * Carrega as informacoes de um usuario
	 * @return ERROR || SUCCESS
	 */
	public String carregarUsuario() {
		if (usuario != null && usuario.getNuUsuario() != null) {
			try {
				listSitio = sitioDao.list();
				usuario = usuarioDao.select(usuario.getNuUsuario());
				coSenha = "*";
				confirmacaoSenha = "*";
				listSitioAtual = usuario.getListSitio();
				listSitio.removeAll(listSitioAtual);
				for (Sitio sitio : listSitioAtual) {
					sitio.setListPerfil(perfilDao.list(sitio));
					sitio.setListSetor(setorDao.list(sitio));	
					Privilegio privilegio = privilegioDao.select(usuario, sitio);
					sitio.setPerfil(privilegio.getPerfil());
					sitio.getListPerfil().remove(sitio.getPerfil());
					sitio.setSetor(privilegio.getSetor());
					sitio.getListSetor().remove(sitio.getSetor());
				}
				for (Sitio sitio : listSitio) {
					sitio.setListSetor(setorDao.list(sitio));	
					sitio.setListPerfil(perfilDao.list(sitio));
				}
				return SUCCESS;
			} catch (Exception e) {
				logger.error("Erro ao carregar o usuario " + usuario,e);
				return ERROR;
			}
		}
		return ERROR;
	}
	
	/**
	 * Insere o texto predefinido de um usuario
	 * @return SUCCESS
	 */
	public String setTextoPredefinidoUsuario() {
		if (usuario==null){
			usuario= new Usuario(); 
			usuario.setNoUsuario(getText("predefinido.nome"));
			usuario.setNuHierarquia(10);
			usuario.setCoUsuario(getText("predefinido.usuario"));
			usuario.setNoEmail(getText("predefinido.email"));
			usuario.setNuTelefone(getText("predefinido.telefone"));
			usuario.setCoSenha(getText("predefinido.senha"));
			getListSitio();
			for (Sitio sitio : listSitio) {
				sitio.setListPerfil(perfilDao.list(sitio));
				sitio.setListSetor(setorDao.list(sitio));
			}			
		}
		return SUCCESS;
	}
	
	/**
	 * Define o sitio em que o usuario esta trabalhando.<br>
	 * Esta informacao fica em sessao
	 * @return SUCCESS || INPUT
	 */
	public String escolherSitio(){
		if(arraySitios == null || arraySitios.length == 0){
			return INPUT; 
		}else{
			try{
				Sitio sitio = sitioDao.select(Long.parseLong(arraySitios[0]));
				Usuario usuario = getUsuarioLogado();
				Privilegio privilegio = privilegioDao.select(usuario, sitio);
				//se alguem mudar o metodo implementando de outra forma
				if(privilegio==null) return INPUT;
				getRequest().getSession().setAttribute(Super.SITIO_LOGADO, sitio);
				getRequest().getSession().setAttribute(Gerenciador.KEY_ULTIMO_SITIO, sitio);//sitio do visitante do site
				
				usuario.setPerfil(privilegio.getPerfil());
				usuario.setSetor(privilegio.getSetor());
				getRequest().getSession().setAttribute(LoginInterceptor.USER_HANDLE, usuario);
				return SUCCESS;
			}catch(NoResultException e){
				//erro esperado
				addActionError("Voc&ecirc; n&atilde;o tem privil&eacute;gio para este site.");
				return INPUT;
			}catch (Exception e) {
				//erro inesperado
				logger.error("Erro ao escolher sitio",e);
				return INPUT;
			}
		}
	}

	public Usuario getUsuario() {
		return usuario;
	}

	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	public String getCoSenha() {
		return coSenha;
	}

	public void setCoSenha(String coSenha) {
		this.coSenha = coSenha;
	}

	public String getConfirmacaoSenha() {
		return confirmacaoSenha;
	}

	public void setConfirmacaoSenha(String confirmacaoSenha) {
		this.confirmacaoSenha = confirmacaoSenha;
	}

	public List<Setor> getListSetor() {
		if (listSetor == null) {
			listSetor = setorDao.getListSetor();
		}
		return listSetor;
	}

	public void setListSetor(List<Setor> listSetor) {
		this.listSetor = listSetor;
	}
	
	public String getSenhaAtual() {
		return senhaAtual;
	}

	public void setSenhaAtual(String senhaAtual) {
		this.senhaAtual = senhaAtual;
	}
	
	public List<Sitio> getListSitio() {
		if (listSitio == null)
			listSitio = getUsuarioLogado().getListSitio();
		return listSitio;
	}

	public void setListSitio(List<Sitio> listSitio) {
		this.listSitio = listSitio;
	}

	public String[] getArraySitios() {
		return arraySitios;
	}

	public void setArraySitios(String[] arraySitios) {
		this.arraySitios = arraySitios;
	}
	
	public Sitio[] getArraySitiosAtuais() {
		return arraySitiosAtuais;
	}

	public void setArraySitiosAtuais(Sitio[] arraySitiosAtuais) {
		this.arraySitiosAtuais = arraySitiosAtuais;
	}

	public List<Usuario> getListUsuario() {
		return listUsuario;
	}

	public void setListUsuario(List<Usuario> listUsuario) {
		this.listUsuario = listUsuario;
	}
	public List<Sitio> getListSitioAtual() {
		return listSitioAtual;
	}

	public void setListSitioAtual(List<Sitio> listSitioAtual) {
		this.listSitioAtual = listSitioAtual;
	}
}
